home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume24 / namei < prev    next >
Encoding:
Internet Message Format  |  1991-06-05  |  11.0 KB

  1. Subject:  v24i087:  A program to trace through symlinks
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 6665b1eb fb4b370c d97bf4ca 713902c0
  5.  
  6. Submitted-by: Roger Southwick <rogers@fangorn.wr.tek.com>
  7. Posting-number: Volume 24, Issue 87
  8. Archive-name: namei
  9.  
  10. [ I wrote the Makefile.  --r$ ]
  11.  
  12. This program takes a set of pathnames.  It scans each component in turn and
  13. follows symlinks until it reaches the end of the pathname.  It prints
  14. the results of interpreting each directory component.  Requires the lstat
  15. system call and the S_IFLINK inode type.
  16.  
  17.     -Roger (rogers@fangorn.wr.tek.com)
  18.  
  19. #! /bin/sh
  20. # This is a shell archive.  Remove anything before this line, then unpack
  21. # it by saving it into a file and typing "sh file".  To overwrite existing
  22. # files, type "sh file -c".  You can also feed this as standard input via
  23. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  24. # will see the following message at the end:
  25. #        "End of archive 1 (of 1)."
  26. # Contents:  README namei.1 namei.c
  27. # Wrapped by rogers@fangorn on Wed Mar 20 17:51:06 1991
  28. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  29. if test -f README -a "${1}" != "-c" ; then 
  30.   echo shar: Will not over-write existing file \"README\"
  31. else
  32. echo shar: Extracting \"README\" \(989 characters\)
  33. sed "s/^X//" >README <<'END_OF_README'
  34. XTired of running into "Too many levels of symlinks" problems on
  35. Xyour 4.2 BSD derivitive machine?  
  36. X
  37. XWe sure did... our NFS'ed network of lots of Suns, Vaxen and so forth
  38. Xmade it impossible at times to trace down where a file REALLY lived.
  39. XI mean ls -l is nice, but wouldn't you like to follow things like
  40. Xthe namei routine in the kernel does?
  41. X
  42. XWell here it is.... the namei program.  It follows things out until
  43. Xa terminal state is found.
  44. X
  45. XThis program compiles and runs under:
  46. X
  47. X    SunOS 4.0.1 (sun3's)
  48. X    SunOS 4.0.3 (sun4's)
  49. X    SunOS 4.1.1 (sun4's)
  50. X    Ultrix 3.1
  51. X    BSD 4.3
  52. X
  53. Xand probably a host of other 4.2 derived systems (but probably not
  54. XSystem V).
  55. X
  56. XAnyway, if anyone has any bugs (or enhancements), please send them to
  57. Xme in E-mail form.
  58. X
  59. XAnd, by the way, if you make LOTS of money off of this program, please
  60. Xdon't tell me :-).
  61. X
  62. X    -Roger      (rogers@fangorn.wr.tek.com)
  63. X        UUCP:    ...!uunet!tektronix!fangorn.wr.tek.com!rogers
  64. X        ARPA:    <rogers%fangorn.wr.tek.com@RELAY.CS.NET>
  65. END_OF_README
  66. if test 989 -ne `wc -c <README`; then
  67.     echo shar: \"README\" unpacked with wrong size!
  68. fi
  69. # end of overwriting check
  70. fi
  71. if test -f namei.1 -a "${1}" != "-c" ; then 
  72.   echo shar: Will not over-write existing file \"namei.1\"
  73. else
  74. echo shar: Extracting \"namei.1\" \(1496 characters\)
  75. sed "s/^X//" >namei.1 <<'END_OF_namei.1'
  76. X.\" 
  77. X.\" Version 1.4 of namei
  78. X.\"
  79. X.TH NAMEI 1 "Local"
  80. X.SH NAME
  81. Xnamei - follow a pathname until a terminal point is found
  82. X.SH SYNOPSIS
  83. X.B namei
  84. X.I [-mx]
  85. X.I pathname
  86. X.I "[ pathname ... ]"
  87. X.SH DESCRIPTION
  88. X.I Namei
  89. Xuses its arguments as pathnames to any type
  90. Xof Unix file (symlinks, files, directories, and so forth). 
  91. X.I Namei
  92. Xthen follows each pathname until a terminal 
  93. Xpoint is found (a file, directory, char device, etc).
  94. XIf it finds a symbolic link, we show the link, and start
  95. Xfollowing it, indenting the output to show the context.
  96. X.PP
  97. XThis program is useful for finding a "too many levels of
  98. Xsymbolic links" problems.
  99. X.PP
  100. XFor each line output,
  101. X.I namei
  102. Xoutputs a the following characters to identify the file types found:
  103. X.LP
  104. X.nf
  105. X   f: = the pathname we are currently trying to resolve
  106. X    d = directory
  107. X    l = symbolic link (both the link and it's contents are output)
  108. X    s = socket
  109. X    b = block device
  110. X    c = character device
  111. X    - = regular file
  112. X    ? = an error of some kind
  113. X.fi
  114. X.PP
  115. X.I Namei
  116. Xprints an informative message when
  117. Xthe maximum number of symbolic links this system can have has been exceeded.
  118. X.SH OPTIONS
  119. X.TP 8
  120. X.B -x
  121. XShow mount point directories with a 'D', rather than a 'd'.
  122. X.TP 8
  123. X.B -m
  124. XShow the mode bits of each file type in octal notation.
  125. X.SH AUTHOR
  126. XRoger Southwick  (rogers@amadeus.wr.tek.com)
  127. X.SH BUGS
  128. XTo be discovered.
  129. X.SH CAVEATS
  130. X.I Namei
  131. Xwill follow an infinite loop of symbolic links forever.  To escape, use
  132. XSIGINT (usually ^C).
  133. X.SH "SEE ALSO"
  134. Xls(1), stat(1)
  135. END_OF_namei.1
  136. if test 1496 -ne `wc -c <namei.1`; then
  137.     echo shar: \"namei.1\" unpacked with wrong size!
  138. fi
  139. # end of overwriting check
  140. fi
  141. if test -f namei.c -a "${1}" != "-c" ; then 
  142.   echo shar: Will not over-write existing file \"namei.c\"
  143. else
  144. echo shar: Extracting \"namei.c\" \(5724 characters\)
  145. sed "s/^X//" >namei.c <<'END_OF_namei.c'
  146. X/*-------------------------------------------------------------
  147. X
  148. XThe namei program
  149. X
  150. XBy: Roger S. Southwick
  151. X
  152. XMay 2, 1990
  153. X
  154. Xusage: namei pathname [pathname ... ]
  155. X
  156. XThis program reads it's arguments as pathnames to any type
  157. Xof Unix file (symlinks, files, directories, and so forth). 
  158. XThe program then follows each pathname until a terminal 
  159. Xpoint is found (a file, directory, char device, etc).
  160. XIf it finds a symbolic link, we show the link, and start
  161. Xfollowing it, indenting the output to show the context.
  162. X
  163. XThis program is useful for finding a "too many levels of
  164. Xsymbolic links" problems.
  165. X
  166. XFor each line output, the program puts a file type first:
  167. X
  168. X   f: = the pathname we are currently trying to resolve
  169. X    d = directory
  170. X    D = directory that is a mount point
  171. X    l = symbolic link (both the link and it's contents are output)
  172. X    s = socket
  173. X    b = block device
  174. X    c = character device
  175. X    - = regular file
  176. X    ? = an error of some kind
  177. X
  178. XThe program prints an informative messages when we exceed
  179. Xthe maximum number of symbolic links this system can have.
  180. X
  181. XThe program exits with a 1 status ONLY if it finds it cannot
  182. Xchdir to /,  or if it encounters an unknown file type.
  183. X
  184. X-------------------------------------------------------------*/
  185. X
  186. X#ifndef lint
  187. Xstatic char *RCSid = "$Id: namei.c,v 1.4 91/03/20 17:44:11 rogers Release_1 $";
  188. X#endif
  189. X
  190. X#include <stdio.h>
  191. X#include <sys/types.h>
  192. X#include <sys/stat.h>
  193. X#include <sys/param.h>
  194. X
  195. Xextern char *sys_errlist[];
  196. Xextern int errno;
  197. X#define ERR    sys_errlist[errno],errno
  198. X
  199. Xint symcount;
  200. Xint mflag = 0;
  201. Xint xflag = 0;
  202. X
  203. Xmain(argc, argv)
  204. Xint argc;
  205. Xchar *argv[];
  206. X{
  207. X    void namei(), usage();
  208. X    char *getwd();
  209. X    int getopt();
  210. X    extern int optind;
  211. X    register int c;
  212. X    char curdir[MAXPATHLEN];
  213. X
  214. X    if(argc < 2)
  215. X    usage();
  216. X
  217. X    while((c = getopt(argc, argv, "mx")) != EOF){
  218. X    switch(c){
  219. X        case 'm':
  220. X        mflag++;
  221. X        break;
  222. X        
  223. X        case 'x':
  224. X        xflag++;
  225. X        break;
  226. X
  227. X        case '?':
  228. X        default:
  229. X        usage();
  230. X    }
  231. X    }
  232. X
  233. X    if(getwd(curdir) == NULL){
  234. X    (void)fprintf(stderr, "namei: unable to get current directory - %s\n", curdir);
  235. X    exit(1);
  236. X    }
  237. X
  238. X
  239. X    for(; optind < argc; optind++){
  240. X    (void)printf("f: %s\n", argv[optind]);
  241. X    symcount = 1;
  242. X    namei(argv[optind], 0);
  243. X
  244. X    if(chdir(curdir) == -1){
  245. X        (void)fprintf(stderr, "namei: unable to chdir to %s - %s (%d)\n", curdir, ERR);
  246. X        exit(1);
  247. X    }
  248. X    }
  249. X    exit(0);
  250. X}
  251. X
  252. Xvoid
  253. Xusage()
  254. X{
  255. X    (void)fprintf(stderr,"usage: namei [-mx] pathname [pathname ...]\n");
  256. X    exit(1);
  257. X}
  258. X
  259. X#ifndef NODEV
  260. X#define NODEV        (dev_t)(-1)
  261. X#endif
  262. X
  263. Xvoid
  264. Xnamei(file, lev)
  265. X
  266. Xregister char *file;
  267. Xregister int lev;
  268. X{
  269. X    register char *cp;
  270. X    char buf[BUFSIZ], sym[BUFSIZ];
  271. X    struct stat stb;
  272. X    register int i;
  273. X    dev_t lastdev = NODEV;
  274. X
  275. X    /*
  276. X     * See if the file has a leading /, and if so cd to root
  277. X     */
  278. X    
  279. X    if(*file == '/'){
  280. X    while(*file == '/')
  281. X        file++;
  282. X    
  283. X    if(chdir("/") == -1){
  284. X        (void)fprintf(stderr,"namei: could not chdir to root!\n");
  285. X        exit(1);
  286. X    }
  287. X    for(i = 0; i < lev; i++)
  288. X        (void)printf("  ");
  289. X
  290. X    if(stat("/", &stb) == -1){
  291. X        (void)fprintf(stderr, "namei: could not stat root!\n");
  292. X        exit(1);
  293. X    }
  294. X    lastdev = stb.st_dev;
  295. X
  296. X    if(mflag)
  297. X        (void)printf(" d %04o /\n", stb.st_mode & 07777);
  298. X    else
  299. X        (void)printf(" d /\n");
  300. X    }
  301. X
  302. X    for(;;){
  303. X
  304. X    /*
  305. X     * Copy up to the next / (or nil) into buf
  306. X     */
  307. X    
  308. X    for(cp = buf; *file != '\0' && *file != '/'; cp++, file++)
  309. X        *cp = *file;
  310. X    
  311. X    while(*file == '/')    /* eat extra /'s    */
  312. X        file++;
  313. X
  314. X    *cp = '\0';
  315. X
  316. X    if(buf[0] == '\0'){
  317. X
  318. X        /*
  319. X         * Buf is empty, so therefore we are done
  320. X         * with this level of file
  321. X         */
  322. X
  323. X        return;
  324. X    }
  325. X
  326. X    for(i = 0; i < lev; i++)
  327. X        (void)printf("  ");
  328. X
  329. X    /*
  330. X     * See what type of critter this file is
  331. X     */
  332. X    
  333. X    if(lstat(buf, &stb) == -1){
  334. X        (void)printf(" ? %s - %s (%d)\n", buf, ERR);
  335. X        return;
  336. X    }
  337. X
  338. X    switch(stb.st_mode & S_IFMT){
  339. X        case S_IFDIR:
  340. X
  341. X        /*
  342. X         * File is a directory, chdir to it
  343. X         */
  344. X        
  345. X        if(chdir(buf) == -1){
  346. X            (void)printf(" ? could not chdir into %s - %s (%d)\n", buf, ERR );
  347. X            return;
  348. X        }
  349. X        if(xflag && lastdev != stb.st_dev && lastdev != NODEV){
  350. X            /* Across mnt point */
  351. X            if(mflag)
  352. X            (void)printf(" D %04o %s\n", stb.st_mode & 07777, buf);
  353. X            else
  354. X            (void)printf(" D %s\n", buf);
  355. X        }
  356. X        else {
  357. X            if(mflag)
  358. X            (void)printf(" d %04o %s\n", stb.st_mode & 07777, buf);
  359. X            else
  360. X            (void)printf(" d %s\n", buf);
  361. X        }
  362. X        lastdev = stb.st_dev;
  363. X
  364. X        (void)fflush(stdout);
  365. X        break;
  366. X
  367. X        case S_IFLNK:
  368. X        /*
  369. X         * Sigh, another symlink.  Read it's contents and
  370. X         * call namei()
  371. X         */
  372. X        
  373. X        bzero(sym, BUFSIZ);
  374. X        if(readlink(buf, sym, BUFSIZ) == -1){
  375. X            (void)printf(" ? problems reading symlink %s - %s (%d)\n", buf, ERR);
  376. X            return;
  377. X        }
  378. X
  379. X        if(mflag)
  380. X            (void)printf(" l %04o %s -> %s", stb.st_mode & 07777, buf, sym);
  381. X        else
  382. X            (void)printf(" l %s -> %s", buf, sym);
  383. X
  384. X        if(symcount > 0 && symcount++ > MAXSYMLINKS){
  385. X            (void)printf("  *** EXCEEDED UNIX LIMIT OF SYMLINKS ***");
  386. X            symcount = -1;
  387. X        }
  388. X        (void)printf("\n");
  389. X        namei(sym, lev + 1);
  390. X        break;
  391. X
  392. X        case S_IFCHR:
  393. X        if(mflag)
  394. X            (void)printf(" c %04o %s\n", stb.st_mode & 07777, buf);
  395. X        else
  396. X            (void)printf(" c %s\n", buf);
  397. X        break;
  398. X        
  399. X        case S_IFBLK:
  400. X        if(mflag)
  401. X            (void)printf(" b %04o %s\n", stb.st_mode & 07777, buf);
  402. X        else
  403. X            (void)printf(" b %s\n", buf);
  404. X        break;
  405. X        
  406. X        case S_IFSOCK:
  407. X        if(mflag)
  408. X            (void)printf(" s %04o %s\n", stb.st_mode & 07777, buf);
  409. X        else
  410. X            (void)printf(" s %s\n", buf);
  411. X        break;
  412. X
  413. X        case S_IFREG:
  414. X        if(mflag)
  415. X            (void)printf(" - %04o %s\n", stb.st_mode & 07777, buf);
  416. X        else
  417. X            (void)printf(" - %s\n", buf);
  418. X        break;
  419. X        
  420. X        default:
  421. X        (void)fprintf(stderr,"namei: unknown file type 0%06o on file %s\n", stb.st_mode, buf );
  422. X        exit(1);
  423. X        
  424. X    }
  425. X    }
  426. X}
  427. X
  428. END_OF_namei.c
  429. if test 5724 -ne `wc -c <namei.c`; then
  430.     echo shar: \"namei.c\" unpacked with wrong size!
  431. fi
  432. # end of overwriting check
  433. fi
  434. echo shar: End of archive 1 \(of 1\).
  435. cp /dev/null ark1isdone
  436. MISSING=""
  437. for I in 1 ; do
  438.     if test ! -f ark${I}isdone ; then
  439.     MISSING="${MISSING} ${I}"
  440.     fi
  441. done
  442. if test "${MISSING}" = "" ; then
  443.     echo You have unpacked all 1 archives.
  444.     rm -f ark[1-9]isdone
  445. else
  446.     echo You still need to unpack the following archives:
  447.     echo "        " ${MISSING}
  448. fi
  449. ##  End of shell archive.
  450. exit 0
  451. --
  452.     -Roger      (rogers@fangorn.wr.tek.com)
  453.         UUCP:    ...!uunet!tektronix!fangorn.wr.tek.com!rogers
  454.         ARPA:    <rogers%fangorn.wr.tek.com@RELAY.CS.NET>
  455.  
  456. exit 0 # Just in case...
  457.